package com.guoxin.artconcurrency.chapter5;


import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * @author guoxin
 * @date 2019/7/25
 */
public class Mutex implements Lock {

    /**
     * 静态内部类，自定义同步器
     */
    private static class Sync extends AbstractQueuedSynchronizer {
        /**
         * 是否处于占用状态
         * （当前同步器是否在独占模式下被线程占用，一般该方法表示是否被当前线程所独占）
         */
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        /**
         * 当状态为0的时候获取锁
         * （独占式获取同步状态，实现该方法需要查询当前状态并判断同步状态是否符合预期，
         * 然后再进行CAS设置同步状态）
         */
        @Override
        protected boolean tryAcquire(int arg) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        /**
         * 释放锁，将状态设置为0
         * （独占式释放同步状态，等待获取同步状态的线程有机会获取同步状态）
         */
        @Override
        protected boolean tryRelease(int arg) {
            if (getState() == 0) {
                throw new IllegalMonitorStateException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        /**
         * 返回一个Condition，每个condition都包含了一个condition队列
         */
        Condition newCondition() {
            return new ConditionObject();
        }
    }

    private final Sync sync = new Sync();


    @Override
    public void lock() {
        /*
         * 独占式获取同步状态，如果当前线程获取同步状态成功，
         * 则由该方法返回，否则，将会进入同步队列等待，
         * 该方法将会调用重写的tryAcquire(int arg)方法
         */
        sync.acquire(1);
    }


    @Override
    public void lockInterruptibly() throws InterruptedException {
        /*
         * 与acquire(int arg)相同，但是该方法响应中断，
         * 当前线程未获取到同步状态而进入同步队列中，
         * 如果当前线程被中断，则该方法会抛出InterruptedException并返回
         */
        sync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        /*
         * 在acquireInterruptibly(int arg)基础上增加了超时限制，
         * 如果当前线程在超时时间内没有获取到同步状态，
         * 那么将会返回false如果获取到返回true
         */
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }

    @Override
    public void unlock() {
        /*
         * 独占式的释放同步状态，该方法会在释放同步状态之后，
         * 将同步队列中第一个节点包含的线程唤醒
         */
        sync.release(1);
    }

    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }

    public boolean isLocked() {
        return sync.isHeldExclusively();
    }

    public boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

}
